package spring.cloud.tasks.api.controller;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import spring.cloud.tasks.api.database.entity.StatisticsDto;
import spring.cloud.tasks.api.domain.ZooKeeperCluster;
import spring.cloud.tasks.api.service.DashboardService;
import spring.cloud.tasks.api.service.ZooKeeperService;
import spring.cloud.tasks.api.service.impl.DashboardServiceImpl;
import spring.cloud.tasks.api.utils.Response;

import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Map;

@RequestMapping("/console/dashboard")
public class DashboardController {

    @Autowired
    private DashboardService dashboardService;
    @Autowired
    private ZooKeeperService zooKeeperService;

    @GetMapping(value = "/count")
    public Response getStatistics(@RequestParam(required = false) String zooKeeperClusterKey)
            throws RuntimeException {
        Map<String, Integer> countMap = Maps.newHashMap();
        int executorInDockerCount = 0;
        int executorNotInDockerCount = 0;
        int jobCount = 0;
        int domainCount = 0;

        List<ZooKeeperCluster> zooKeeperClusterList = null;
        if (StringUtils.isNotBlank(zooKeeperClusterKey)) {
            ZooKeeperCluster zooKeeperCluster = zooKeeperService.getZooKeeperCluster(zooKeeperClusterKey);
            zooKeeperClusterList = Lists.newArrayList();
            zooKeeperClusterList.add(zooKeeperCluster);
        } else {
            zooKeeperClusterList = zooKeeperService.getZooKeeperClusterList();
        }

        for (ZooKeeperCluster zooKeeperCluster : zooKeeperClusterList) {
            // 不统计离线的zkcluster
            if (zooKeeperCluster.isOffline()) {
                continue;
            }

            String zooKeeperAddress = zooKeeperCluster.getZooKeeperAddress();
            if (zooKeeperAddress != null) {
                executorInDockerCount += dashboardService.executorInDockerCount(zooKeeperAddress);
                executorNotInDockerCount += dashboardService.executorNotInDockerCount(zooKeeperAddress);
                jobCount += dashboardService.jobCount(zooKeeperAddress);
            }
            domainCount += zooKeeperService.domainCount(zooKeeperCluster.getZooKeeperClusterKey());
        }

        countMap.put("executorInDockerCount", executorInDockerCount);
        countMap.put("executorNotInDockerCount", executorNotInDockerCount);
        countMap.put("jobCount", jobCount);
        countMap.put("domainCount", domainCount);
        return Response.success(countMap);
    }

    @GetMapping(value = "/top10FailJob")
    public Response top10FailJob(@RequestParam(required = false) String zooKeeperClusterKey)
            throws RuntimeException {
        if (StringUtils.isNotBlank(zooKeeperClusterKey)) {
            ZooKeeperCluster zooKeeperCluster = checkAndGetZkCluster(zooKeeperClusterKey);
            StatisticsDto ss = dashboardService.top10FailureJob(zooKeeperCluster.getZooKeeperAddress());
            return ss == null ? new Response() : Response.success(ss.getResult());
        }

        return Response.success(dashboardService.top10FailureJobByAllZkCluster());
    }

    private ZooKeeperCluster checkAndGetZkCluster(String zooKeeperClusterKey) throws RuntimeException {
        ZooKeeperCluster zooKeeperCluster = zooKeeperService.getZooKeeperCluster(zooKeeperClusterKey);
        if (zooKeeperCluster == null) {
            throw new RuntimeException("zk clsuter " + zooKeeperClusterKey + "不存在");
        }
        return zooKeeperCluster;
    }

    @GetMapping(value = "/top10FailExecutor")
    public Response top10FailExecutor(@RequestParam(required = false) String zooKeeperClusterKey)
            throws RuntimeException {
        if (StringUtils.isNotBlank(zooKeeperClusterKey)) {
            ZooKeeperCluster zooKeeperCluster = checkAndGetZkCluster(zooKeeperClusterKey);
            StatisticsDto statisticsDto = dashboardService.top10FailureExecutor(zooKeeperCluster.getZooKeeperAddress());
            return statisticsDto == null ? new Response() : Response.success(statisticsDto.getResult());
        }
        return Response.success(dashboardService.top10FailureExecutorByAllZkCluster());
    }

    @GetMapping(value = "/top10ActiveJob")
    public Response top10ActiveJob(@RequestParam(required = false) String zooKeeperClusterKey)
            throws RuntimeException {
        if (StringUtils.isNotBlank(zooKeeperClusterKey)) {
            ZooKeeperCluster zooKeeperCluster = checkAndGetZkCluster(zooKeeperClusterKey);
            StatisticsDto ss = dashboardService.top10AactiveJob(zooKeeperCluster.getZooKeeperAddress());
            return ss == null ? new Response() : Response.success(ss.getResult());
        }
        return Response.success(dashboardService.top10AactiveJobByAllZkCluster());
    }

    @GetMapping(value = "/top10LoadJob")
    public Response top10LoadJob(@RequestParam(required = false) String zooKeeperClusterKey)
            throws RuntimeException {
        if (StringUtils.isNotBlank(zooKeeperClusterKey)) {
            ZooKeeperCluster zooKeeperCluster = checkAndGetZkCluster(zooKeeperClusterKey);
            StatisticsDto ss = dashboardService.top10LoadJob(zooKeeperCluster.getZooKeeperAddress());
            return ss == null ? new Response() : Response.success(ss.getResult());
        }
        return Response.success(dashboardService.top10LoadJobByAllZkCluster());
    }

    @GetMapping(value = "/top10FailDomain")
    public Response top10FailDomain(@RequestParam(required = false) String zkClusterKey)
            throws RuntimeException {
        if (StringUtils.isNotBlank(zkClusterKey)) {
            ZooKeeperCluster zooKeeperCluster = checkAndGetZkCluster(zkClusterKey);
            StatisticsDto ss = dashboardService.top10FailureDomain(zooKeeperCluster.getZooKeeperAddress());
            return ss == null ? new Response() : Response.success(ss.getResult());
        }
        return Response.success(dashboardService.top10FailureDomainByAllZkCluster());
    }

    @GetMapping(value = "/top10UnstableDomain")
    public Response top10UnstableDomain(@RequestParam(required = false) String zkClusterKey)
            throws RuntimeException {
        if (StringUtils.isNotBlank(zkClusterKey)) {
            ZooKeeperCluster zkCluster = checkAndGetZkCluster(zkClusterKey);
            StatisticsDto ss = dashboardService.top10UnstableDomain(zkCluster.getZooKeeperAddress());
            return ss == null ? new Response() : Response.success(ss.getResult());
        }
        return Response.success(dashboardService.top10UnstableDomainByAllZkCluster());
    }

    @GetMapping(value = "/top10LoadExecutor")
    public Response top10LoadExecutor(@RequestParam(required = false) String zkClusterKey)
            throws RuntimeException {
        if (StringUtils.isNotBlank(zkClusterKey)) {
            ZooKeeperCluster zkCluster = checkAndGetZkCluster(zkClusterKey);
            StatisticsDto ss = dashboardService.top10LoadExecutor(zkCluster.getZooKeeperAddress());
            return ss == null ? new Response() : Response.success(ss.getResult());
        }
        return Response.success(dashboardService.top10LoadExecutorByAllZkCluster());
    }

    @GetMapping(value = "/domainProcessCount")
    public Response domainProcessCount(@RequestParam(required = false) String zkClusterKey)
            throws RuntimeException {
        if (StringUtils.isNotBlank(zkClusterKey)) {
            ZooKeeperCluster zkCluster = checkAndGetZkCluster(zkClusterKey);
            StatisticsDto ss = dashboardService.allProcessAndErrorCountOfTheDay(zkCluster.getZooKeeperAddress());
            return ss == null ? new Response() : Response.success(ss.getResult());
        }
        return Response.success(dashboardService.allProcessAndErrorCountOfTheDayByAllZkCluster());
    }

    @GetMapping(value = "/domainRank")
    public Response loadDomainRank(@RequestParam(required = false) String zkClusterKey)
            throws RuntimeException {
        if (StringUtils.isNotBlank(zkClusterKey)) {
            return Response.success(dashboardService.loadDomainRankDistribution(zkClusterKey));
        }
        return Response.success(dashboardService.loadDomainRankDistributionByAllZkCluster());
    }

    @GetMapping(value = "/jobRank")
    public Response loadJobRank(@RequestParam(required = false) String zkClusterKey)
            throws RuntimeException {
        if (StringUtils.isNotBlank(zkClusterKey)) {
            ZooKeeperCluster zkCluster = checkAndGetZkCluster(zkClusterKey);
            return Response.success(dashboardService.loadJobRankDistribution(zkCluster.getZooKeeperAddress()));
        }
        return Response.success(dashboardService.loadJobRankDistributionByAllZkCluster());
    }

    @GetMapping(value = "/domainExecutorVersionNumber")
    public Response versionDomainNumber(@RequestParam(required = false) String zkClusterKey)
            throws RuntimeException {
        if (StringUtils.isNotBlank(zkClusterKey)) {
            ZooKeeperCluster zkCluster = checkAndGetZkCluster(zkClusterKey);
            return Response.success(dashboardService.versionDomainNumber(zkCluster.getZooKeeperAddress()));
        }
        return Response.success(dashboardService.versionDomainNumberByAllZkCluster());
    }

    @GetMapping(value = "/executorVersionNumber")
    public Response versionExecutorNumber(@RequestParam(required = false) String zkClusterKey)
            throws RuntimeException {
        if (StringUtils.isNotBlank(zkClusterKey)) {
            ZooKeeperCluster zkCluster = checkAndGetZkCluster(zkClusterKey);
            return Response.success(dashboardService.versionExecutorNumber(zkCluster.getZooKeeperAddress()));
        }
        return Response.success(dashboardService.versionExecutorNumberByAllZkCluster());
    }

    //@Audit
    @PostMapping(value = "/namespaces/{namespace:.+}/shardingCount/clean")
    public Response cleanShardingCount(@PathVariable String namespace) throws RuntimeException {
        //assertIsSystemAdmin();
        dashboardService.cleanShardingCount(namespace);
        return new Response();
    }

    //@Audit
    @PostMapping(value = "/namespaces/{namespace:.+}/jobs/{jobName}/jobAnalyse/clean")
    public Response cleanJobAnalyse(@PathVariable String namespace,
                                    @PathVariable String jobName) throws RuntimeException {
        //assertIsSystemAdmin();
        dashboardService.cleanOneJobAnalyse(namespace, jobName);
        return new Response();
    }

    //@Audit
    @PostMapping(value = "/namespaces/{namespace:.+}/jobAnalyse/clean")
    public Response cleanJobsAnalyse(@PathVariable String namespace)
            throws RuntimeException {
        //assertIsSystemAdmin();
        dashboardService.cleanAllJobAnalyse(namespace);
        return new Response();
    }

    //@Audit
    @PostMapping(value = "/namespaces/{namespace:.+}/tasks/{taskId}/taskExecutorCount/clean")
    public Response cleanJobExecutorCount(@PathVariable String nameSpace,
                                          @PathVariable String taskId) throws RuntimeException {
        //assertIsSystemAdmin();
        dashboardService.cleanOneJobExecutorCount(nameSpace, taskId);
        return new Response();
    }

    @GetMapping(value = "/domainOperationCount")
    public Response domainOperationCount(@RequestParam(required = false) String zooKeeperClusterKey) {
        Date today = new Date();
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(today);
        calendar.add(Calendar.DATE, -30);
        Date startDate = calendar.getTime();
        Map<String, List> histories = dashboardService
                .getDomainOperationHistory(DashboardServiceImpl.DashboardType.DOMAIN.name(),
                        DashboardServiceImpl.DashboardTopic.DOMAIN_OVERALL_COUNT.name(), startDate, today);
        return Response.success(histories);
    }

    @GetMapping(value = "/domainCount")
    public Response domainCount(@RequestParam(required = false) String zooKeeperClusterKey) {
        Date today = new Date();
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(today);
        calendar.add(Calendar.DATE, -30);
        Date startDate = calendar.getTime();
        Map<String, List> histories = dashboardService
                .getDomainCountHistory(zooKeeperClusterKey, DashboardServiceImpl.DashboardType.DOMAIN.name(),
                        DashboardServiceImpl.DashboardTopic.DOMAIN_COUNT.name(), startDate, today);
        return Response.success(histories);
    }

    @GetMapping(value = "/executorCount")
    public Response executorCount(@RequestParam(required = false) String zooKeeperClusterKey) {
        Date today = new Date();
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(today);
        calendar.add(Calendar.DATE, -30);
        Date startDate = calendar.getTime();
        Map<String, List> histories = dashboardService
                .getExecutorHistory(zooKeeperClusterKey, DashboardServiceImpl.DashboardType.EXECUTOR.name(),
                        DashboardServiceImpl.DashboardTopic.EXECUTOR_COUNT.name(), startDate, today);
        return Response.success(histories);
    }

    @GetMapping(value = "/jobCount")
    public Response jobCount(@RequestParam(required = false) String zooKeeperClusterKey) {
        Date today = new Date();
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(today);
        calendar.add(Calendar.DATE, -30);
        Date startDate = calendar.getTime();
        Map<String, List> histories = dashboardService
                .getJobCountHistory(zooKeeperClusterKey, DashboardServiceImpl.DashboardType.JOB.name(),
                        DashboardServiceImpl.DashboardTopic.JOB_COUNT.name(), startDate, today);
        return Response.success(histories);
    }

}
